package com.logistics.utils.webservice.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.parser.Feature;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.gson.JsonObject;
import com.logistics.utils.tool.StringUtils;
import com.logistics.utils.webservice.annotation.WebServiceListener;
import com.logistics.utils.webservice.annotation.WebServiceMethod;
import com.logistics.utils.webservice.model.WebServiceResponse;
import com.logistics.utils.webservice.service.IWebService;
import org.apache.commons.lang.ArrayUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Component;
import javax.jws.WebService;
import java.lang.reflect.*;
import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

@Component
@WebService(targetNamespace = "http://server.webservice.example.com",
        endpointInterface = "com.logistics.utils.webservice.service.IWebService")
public class WebServiceImpl implements IWebService {


    @Autowired
    public ApplicationContext applicationContext;

    @Override
    public WebServiceResponse execute(String clazz, String method, String param) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException, ClassNotFoundException, JsonProcessingException, InstantiationException {
        if(StringUtils.isNull(clazz)){
            return WebServiceResponse.build("error", "clazz不能为空", null);
        }
        if(StringUtils.isNull(method)){
            return WebServiceResponse.build("error", "method不能为空", null);
        }
        Map<String, Object> maps = applicationContext.getBeansWithAnnotation(WebServiceListener.class);
        // 获取类名
        String clsName = maps.values().stream().filter(e -> e.getClass().getName().contains(clazz)).
                map(e -> e.getClass().getName().split("\\$\\$")[0]).collect(Collectors.joining());
        if(StringUtils.isNull(clsName)){
            return WebServiceResponse.build("error", "clazz不存在", null);
        }

        Class<?> cls = Class.forName(clsName);
        // 获取服务方法名
        String methodName = Arrays.stream(cls.getMethods()).filter(e -> e.isAnnotationPresent(WebServiceMethod.class)
                && StringUtils.isEquals(e.getName(), method)).map(e -> e.getName()).collect(Collectors.joining());

        Object service = applicationContext.getBean(firstLetter(clazz));

        Method executeMethod = null;
        Parameter[] parameter = null;
        for(Method met : service.getClass().getMethods()){
            if(StringUtils.isEquals(met.getName(), methodName)){
                executeMethod = met;
                parameter = met.getParameters();
                break;
            }
        }
        if(StringUtils.isNull(executeMethod)){
            return WebServiceResponse.build("error", "method不存在", null);
        }
        // 请求参数
        Object[] requestParameter = parameterFormatter(parameter, param);
        Object result = StringUtils.isNotNull(requestParameter) ?  executeMethod.invoke(service, requestParameter)
                : executeMethod.invoke(service);
        return WebServiceResponse.build("success", "成功", result);
    }

    /**
     * 参数转换
     * @param parameters
     * @param param
     * @return
     * @throws JsonProcessingException
     * @throws ClassNotFoundException
     * @throws NoSuchMethodException
     * @throws IllegalAccessException
     * @throws InvocationTargetException
     * @throws InstantiationException
     */
    protected Object[] parameterFormatter(Parameter[] parameters, String param) throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException, JsonProcessingException {
        if(StringUtils.isNull(parameters) || parameters.length == 0 || StringUtils.isNull(param)){
            return null;
        }
        List<Object> list = new LinkedList<>();
        JSONObject jsonObject = JSONObject.parseObject(param, Feature.OrderedField);
        for(Parameter item : parameters){
            if(!item.getType().equals(String.class) &&
                    !item.getType().equals(Integer.class)){
                Class<?> clazz = Class.forName(((Class) item.getParameterizedType()).getName());
                Constructor<?> constructor = clazz.getConstructor();
                Object object = constructor.newInstance();
                Field[] fields = (Field[]) ArrayUtils.addAll(clazz.getDeclaredFields(),
                        clazz.getSuperclass().getDeclaredFields());
                jsonObject.keySet().stream().filter(key -> StringUtils.isNotNull(jsonObject.get(key))).forEach(key -> {
                    Arrays.stream(fields).filter(e -> StringUtils.isEquals(key, e.getName()))
                            .forEach(e -> setValue(e, jsonObject.get(key).toString(), object));
                });
                list.add(object);
            } else {
                if(item.getType().equals(String.class)){
                    jsonObject.keySet().stream().forEach(key -> list.add(jsonObject.get(key).toString()));
                } else if(item.getType().equals(Integer.class) || item.getType().equals(int.class)){
                    jsonObject.keySet().stream().forEach(key -> list.add(Integer.valueOf(jsonObject.get(key).toString())));
                }else if(item.getType().equals(BigDecimal.class)){
                    jsonObject.keySet().stream().forEach(key -> list.add(new BigDecimal(jsonObject.get(key).toString())));
                }else if(item.getType().equals(Long.class) || item.getType().equals(long.class)){
                    jsonObject.keySet().stream().forEach(key -> list.add(new Long(jsonObject.get(key).toString())));
                }
            }
        }
        return list.toArray();
    }

    /**
     * 设置对象值
     * @param field
     * @param value
     * @param object
     * @return
     * @throws IllegalAccessException
     */
    protected Object setValue(Field field, String value, Object object){
        field.setAccessible(true);
        try {
            if(field.getType().equals(Integer.class)){
                field.set(object, Integer.valueOf(value));
            }else if(field.getType().equals(Long.class)){
                field.set(object, new Long(value));
            }else if(field.getType().equals(Boolean.class)){
                field.set(object, new Boolean(value));
            } else if (field.getType().equals(Short.class)){
                field.set(object, new Short(value));
            } else if (field.getType().equals(BigDecimal.class)){
                field.set(object, new BigDecimal(value));
            } else if (field.getType().equals(String.class)){
                field.set(object, value);
            }
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
        return object;
    }

    /**
     * 首字母转小写
     * @param str
     * @return
     */
    protected String firstLetter(String str){
        if (str == null || str.length() == 0) {
            return str;
        }
        StringBuilder sb = new StringBuilder(str);
        sb.replace(0, 1, String.valueOf(Character.toLowerCase(sb.charAt(0))));
        return sb.toString();
    }

}
